<template>
  <div
    class="text-scroll-vertical"
    :class="[{ 'is-hover-stop': true && showEllipsis }, customClass]"
    :style="{
      '--text-container-height': textContainerHeight
        ? `${textContainerHeight}px`
        : 'inherit',
      '--line-height': `${lineHeight}px`,
      '--default-height':  overflowMode === 'height' ? '100%' : 'inherit'
    }"
  >
    <div class="muti-line-scroll" v-if="isOverflowScroll">
      <div
        ref="wrapperRef"
        class="text-scroll-vertical-wrapper"
        :class="{ 'is-animate': showEllipsis }"
        :style="{
          '--duration': `${animateOptions.duration}s`,
          '--delay': `${animateOptions.delay}s`,
          '--direction': `${animateOptions.direction}`,
          '--end-distance': `${animateOptions.endDistance}px`,
          '--space-width': `${animateOptions.spaceWidth}px`,
          '--start-distance': `${animateOptions.startDistance}px`,
        }"
      >
        <div ref="textRef" class="text-inline">
          {{ localValue }}
        </div>
        <div v-if="showEllipsis" class="text-inline copy-text">
          {{ localValue }}
        </div>
      </div>
    </div>

    <div v-else class="muti-line-ellipsis">
      <div class="more" v-show="showEllipsis">...</div>
      <div class="content" ref="textRef">{{ localValue }}</div>
    </div>
  </div>
</template>

<script>
import { nextTick } from "vue";
import { debounce, getLineHeight, observerDom } from "./utils/common";
import useEllipsis from "./mixins/useEllipsis";
import useScroll from "./mixins/useScroll";

export default {
  name: "TextScrollVertical",
  mixins: [useEllipsis, useScroll],
  props: {
    /**
     * # 文本内容
     */
    value: {
      type: String,
      default: "",
    },
    /**
     * # 是否溢出滚动
     * 开启则滚动，不开启显示省略
     */
    isOverflowScroll: {
      type: Boolean,
      default: true,
    },
    /**
     * # 溢出模式
     * 可选值：`height`|`lineClamp`，默认值为`lineClamp`。
     * `height`：内容超出容器高度时溢出
     * `lineClamp`：内容超出指定行数时溢出
     */
    overflowMode: {
      type: String,
      default: "lineClamp",
    },
    /**
     * # 省略行数
     * 该参数只在`overflowMode`为`lineClamp`时有效，默认值为`3`
     * + 滚动模式下，超出行数无限滚动
     * + 省略模式下，超出行数显示省略文本
     */
    lineClamp: {
      type: Number,
      default: 3,
    },
    /**
     * # 省略模式下，是否显示最后一行显示不全的文本，默认值为`true`。
     */
    showLastLine: {
      type: Boolean,
      default: true,
    },
    /**
     * # 滚动动画配置
     * @param duration `number` 动画持续时间（s），滚动一次当前容器宽度所需时长，默认值为`5s`
     * @param delay `number` 动画延迟时间（s）。默认值为`0s`
     * @param direction `string` 动画方向，可选值：`left`|`right`，默认值为`left`
     * @param spaceWidth `number|string` 无限滚动首尾空白宽度，数字为像素值，字符串为百分比值（相对于容器宽度），默认值为`50%`
     * @param hoverStop `boolean` 鼠标悬停时是否停止动画，默认值为`true`
     * @param fixSpeed `number` 固定滚动速度，单位为像素/秒。若设置了固定滚动速度（`fixSpeed > 0`），则`duration`不生效。默认值为`0`
     */
    animateConfig: {
      type: Object,
      default: () => ({}),
    },
    /**
     * # 自定义样式名称
     */
    customClass: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      localValue: "",
      textHeight: 0,
      parentHeight: 0,
      parentWidth: 0,
      // 行高
      lineHeight: 0,
    };
  },
  mounted() {
    this.localValue = this.value;
    this.lineHeight = getLineHeight(this.$el);
    this.computedTextHeight();
    observerDom(
      this.$el,
      debounce(({ height, width }) => {
        this.parentHeight = height;
        // 容器宽度发生变化，重新计算文本高度
        if (this.parentWidth && this.parentWidth !== width) {
          this.computedTextHeight();
        }
        this.parentWidth = width;
      }, 100)
    );
  },
  methods: {
    async computedTextHeight() {
      await nextTick();
      const textRef = this.$refs.textRef;
      if (!textRef) {
        return;
      }
      this.textHeight = textRef.clientHeight;
    },
  },
  watch: {
    value(newValue) {
      this.localValue = newValue;
      this.computedTextHeight();
    },
  },
};
</script>

<style scoped>
.text-scroll-vertical {
  width: 100%;
  height: var(--default-height);
  overflow: hidden;
}
.text-scroll-vertical.is-hover-stop:hover
  .text-scroll-vertical-wrapper.is-animate {
  animation-play-state: paused;
}
.copy-text {
  margin-top: var(--space-width);
}
.text-scroll-vertical-wrapper.is-animate {
  animation: text-scroll-vertical var(--duration) var(--delay) infinite linear;
}

@keyframes text-scroll-vertical {
  0% {
    transform: translateY(var(--start-distance));
  }
  100% {
    transform: translateY(var(--end-distance));
  }
}
.muti-line-ellipsis,
.muti-line-scroll {
  width: 100%;
  height: var(--text-container-height);
  overflow: hidden;
}
.muti-line-ellipsis::before {
  content: "";
  display: block;
  height: calc(var(--text-container-height) - var(--line-height));
}
.muti-line-ellipsis .more {
  float: right;
}
.muti-line-ellipsis .content {
  margin-top: calc(var(--line-height) - var(--text-container-height));
}
</style>
